#pragma once
#include <vector>
#include "RUDPEx.h"
#define CVTLL(x) (((long long)(x)) & 0xffffffff)
#define MAKEUSHORT(a, b) ((unsigned short)((CVTLL(a)) << 8 | CVTLL(b)))
#define MAKEUINT(a,b,c,d)((unsigned int)((CVTLL(MAKEUSHORT(a,b)) << 16) | CVTLL(MAKEUSHORT(c,d))))
class TurnClient
{
public:
	TurnClient(const char* ip, uint32_t port, uint32_t client);
	~TurnClient();

	RUDP* GetUDP();

	void Connect(uint32_t client, uint32_t timeout);

	void Disconnect();

	void Update(uint32_t timeout);

	void SendTo(uint8_t* data, uint32_t size);

	void GetClients();

	template <class _Fx, class _Types>
	void RegisterRecvCallback(_Fx&& _Func, _Types&& _User) {
		onRecv = std::bind(_STD forward<_Fx>(_Func), _User, std::placeholders::_1, std::placeholders::_2);
	}
	template <class _Fx>
	void RegisterRecvCallback(_Fx&& _Func) {
		onRecv = std::bind(_STD forward<_Fx>(_Func), std::placeholders::_1, std::placeholders::_2);
	}
	void UnregisterRecvCallback() {
		onRecv = nullptr;
	}

	template <class _Fx, class _Types>
	void RegisterConnectCompleted(_Fx&& _Func, _Types&& _User) {
		onConnectCompleted = std::bind(_STD forward<_Fx>(_Func), _User, std::placeholders::_1);
	}
	template <class _Fx>
	void RegisterConnectCompleted(_Fx&& _Func) {
		onConnectCompleted = std::bind(_STD forward<_Fx>(_Func), std::placeholders::_1);
	}
	void UnregisterConnectCompleted() {
		onConnectCompleted = nullptr;
	}

	template <class _Fx, class _Types>
	void RegisterGetClients(_Fx&& _Func, _Types&& _User) {
		onGetClients = std::bind(_STD forward<_Fx>(_Func), _User, std::placeholders::_1);
	}
	template <class _Fx>
	void RegisterGetClients(_Fx&& _Func) {
		onGetClients = std::bind(_STD forward<_Fx>(_Func), std::placeholders::_1);
	}
	void UnregisterGetClients() {
		onGetClients = nullptr;
	}

	template <class _Fx, class _Types>
	void RegisterDisconnected(_Fx&& _Func, _Types&& _User) {
		onDisconnected = std::bind(_STD forward<_Fx>(_Func), _User);
	}
	template <class _Fx>
	void RegisterDisconnected(_Fx&& _Func) {
		onDisconnected = std::bind(_STD forward<_Fx>(_Func));
	}
	void UnregisterDisconnected() {
		onDisconnected = nullptr;
	}

private:

	void InternalRecv(uint8_t* buffer, uint32_t len, sockaddr_in* remote, bool reliable, void* user);

	void InternalSend(Message* message, SendState state, void* user);

	void ExceptionDisconnect();

private:

	RUDPEx* rudp = nullptr;

	std::function<void(bool)> onConnectCompleted;
	std::function<void()> onDisconnected;
	std::function<void(uint8_t* buffer, uint32_t len)> onRecv;
	std::function<void(std::vector<uint32_t>)> onGetClients;
	bool isConnected = false;
	bool isConnecting = false;
	uint32_t connectTs = 0;
	uint32_t beginConnectTs = 0;
	uint32_t connectTimeout;
	uint32_t connectSuccessTs;
	uint32_t lastHBTs;

	struct sockaddr_in* targetAddr = nullptr;
	uint32_t selfID, targetID;
	uint64_t selfLID, targetLID;
	uint64_t selfLHID, getClientLHID;
};

